Running Embedded Rust in QEMU
I am interested in expanding my ability to write more stable and flexible embedded programs. As part of that, I am improving my knowledge of virtualization options. For rust applications a somewhat established approach is to use QEMU virtualization. QEMU is a very flexible virtualization platform, which I have used before for faster development of a raspberry pi application.
I am using The Embedded Rust Book as a reference.
To start with a cortex-m project, it is good to start with the templates. A new project can be pulled from them using cargo generate
cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart
The initial main.rs
is
#![no_std]
#![no_main]
use panic_halt as _;
use cortex_m_rt::entry;
#[entry]
fn main() -> ! {
loop {
// your code goes here
}
}
This does not linke the std
crate, but to the subset core
crate. The main
function is set explicitly as the entry point.
This code is fine, but it doesn't do anything. To get started let's add a debug print function, and a exit indicator for the debugger.
#![no_main]
#![no_std]
use panic_halt as _;
use cortex_m_rt::entry;
use cortex_m_semihosting::{debug, hprintln};
#[entry]
fn main() -> ! {
hprintln!("Hello, world!").unwrap();
// exit QEMU
// NOTE do not run this on hardware; it can corrupt OpenOCD state
debug::exit(debug::EXIT_SUCCESS);
loop {}
}
hprintln!
is a macro which is printed using semihosting to QEMU's host. This would also display in a debug session.
To output the binary, the package just has to be built.
cargo build
Then qemu can be run using
$ qemu-system-arm \
-cpu cortex-m3 \
-machine lm3s6965evb \
-nographic \
-semihosting-config enable=on,target=native \
-kernel target/thumbv7m-none-eabi/debug/examples/cortex_demo
This outputs the debug message directly to console, and exits gracefully.